ngx.req.read_body()
local raw = ngx.req.get_body_data()
local json = require "cjson"
local args

pcall(function(raw) args = json.decode(raw) end, raw)

if nil == args then
    ngx.err("no post data")
    return
end

-- 验证参数
local user_id = args.uid
if nil == user_id then
    ngx.say('{"code":10000,"message":"请下载app进行投票"}')
    return
end

local act_id = args.act_id
if nil == act_id then
    ngx.say('{"code":10000, "message":"act_id不能为空"}')
    return
end

local item_ids = args.item_ids
if nil == item_ids then
    ngx.say('{"code":10000,"message":"投票id不能为空"}')
    return
end

local vote_token = args.vote_token
if nil == vote_token then
    ngx.say('{"code":10000,"message":"vote_token不能为空"}')
    return
end


local redis_client = require "lib.redis"
local redis = redis_client:new()

local user, err = redis:hget('app:uid:'..act_id, user_id)

-- 验证是否登录
if nil == user then
    ngx.say('{"code":10000,"message":"请登录后进行投票"}')
    return
end
-- 判断验签是否正确
if vote_token ~= user then
    ngx.say('{"code":10001,"message":"验签不匹配"}')
    return
end

local ways = args.ways
-- 删除验签
if ways ~= "wechat" then
    redis:hset('app:uid:'..act_id, user_id, '')
end

--开始投票
local vote = redis:hmget('rule:'..act_id, 'allow_votes', 'brush_mode', 'start', 'end', 'is_pause', 'max_votes')

if nil == vote then
    ngx.say('{"code":10000, "message":"活动不存在"}')
    return
end

local ids = {}

for _, of in pairs(item_ids) do
    ids[of] = of
end

local t = 0

for _ in pairs(ids) do
    t = t + 1
end

local max_votes = tonumber(vote[6]) or 0

if t > max_votes then
    ngx.say('{"code":10000,"message":"您每次最多只能投', max_votes,'个选项"}')
    return
end

local time = ngx.time()
local is_paused = tonumber(vote[5])

--验证活动是否暂停
if is_paused == 1 then
    ngx.say('{"code":10000, "message":"活动已暂停"}')
    return
end

--验证投票时间
local end_at = vote[4] or (time + 1)
if time > tonumber(end_at) then
    ngx.say('{"code":10000, "message":"活动已经结束"}')
    return
end

local start_at = vote[3] or 0
if time < tonumber(start_at) then
    ngx.say('{"code":10000, "message":"活动还未开始"}')
    return
end


-- 验证投票次数，防刷票
local times_key = table.concat({"times", act_id, user_id}, ":")
local allow_votes = tonumber(vote[1])
local mode = tonumber(vote[2])

if mode == 1 then
    local times_of_everday = redis:hget(times_key, ngx.today())
    local t = tonumber(times_of_everday) or 0
    if t >= allow_votes then
        ngx.say('{"code":10000, "message":"您今天的投票次数已用完"}')
        return
    end
elseif mode == 2 then
    local times_of_life = redis:hget(times_key, 'total')
    local t = tonumber(times_of_life) or 0
    if t >= allow_votes then
        ngx.say('{"code":10000, "message":"您的投票次数已用完"}')
        return
    end
else
    -- ngx.WARN
    ngx.log(ngx.ERR, "error vote brush_mode:", mode)
    ngx.say('{"code":10000, "message":"无效的投票项目"}')
    return    
end

ngx.record_user()
-- 投票计数，并记录相关数据
local ip = args.ip or 'unknow'
local device_id = args.device_id or ""
local location = args.location or ""
local tenant_id = args.TenantID or ""
local uniqueid = string.lower(tenant_id..user_id)

local today = ngx.today()
local now = ngx.now()
local logs_key = "logs:"..act_id..":"..today
local ranking_key = "ranking:"..act_id
local log

-- bengin redis transaction
redis:multi()

for _, id in pairs(ids) do
    log = string.format(
        '{"ip":"%s","user":"%s","item":"%s","vote_at":"%s","device_id":"%s","location":"%s"}',
        ip,
        uniqueid,
        id,
        now,
        device_id,
        location
    )
    redis:zincrby(ranking_key, 1, id)
    redis:lpush(logs_key, log)
end

redis:hincrby(times_key, "total", 1)
redis:hincrby(times_key, today, 1)

-- exec redis transaction
local _, err = redis:exec()

if nil == err then
    ngx.say('{"code":200, "message":"投票成功"}')
else
    ngx.say('{"code":10000, "message":"投票失败"}')
end
